from quant.markets import Channel, Handler
from quant.accounts.api import Api, Spi
from quant.const import Exchange
from quant.exchanges._factory import add_factory
from quant.exchanges.basics import ApiRouter, SpiRouter, FunctionsRouter
from quant.exchanges.binance_swap_usdt import BinanceSwapUsdtChannel, BinanceSwapUsdtHandler, BinanceSwapUsdtApi, BinanceSwapUsdtSpi, BinanceSwapFunctions
from quant.exchanges.binance_spot import BinanceSpotChannel, BinanceSpotHandler, BinanceSpotApi, BinanceSpotSpi, BinanceSpotFunctions


class BinanceChannel(Channel):
    agent: Channel

    def init(self):
        agent_name = get_agent_name(self.symbol)
        agent_cls = _channel_agent_map[agent_name]
        self.agent = agent_cls(self.event, self.exchange, self.symbol, self.frequency, self.markets)

    def connect(self):
        return self.agent.connect()

    def disconnect(self):
        return self.agent.disconnect()

    def is_open(self):
        return self.agent.is_open()


class BinanceHandler(Handler):
    agent: Handler

    def init(self):
        agent_name = get_agent_name(self.symbol)
        agent_cls = _handler_agent_map[agent_name]
        self.agent = agent_cls(self.event, self.exchange, self.symbol, self.frequency, self.markets)

    def process(self, routing_key, recv_time, raw):
        return self.agent.process(routing_key, recv_time, raw)


class BinanceApi(ApiRouter):
    def _create_agent(self):
        params = (self.keys, self.account)
        self.agent_map = {n: cls(*params) for n, cls in _api_agent_map.items()}

    def _get_agent(self, symbol):
        agent_name = get_agent_name(symbol)
        try:
            agent: Api = self.agent_map[agent_name]
        except KeyError:
            err = 'Agent for {} not implemented!'.format(symbol)
            raise NotImplementedError(err)
        return agent


class BinanceSpi(SpiRouter):
    def _create_agent(self):
        params = (self.keys, self.account)
        self.agent_map = {n: cls(*params) for n, cls in _spi_agent_map.items()}

    def _get_agent(self, symbol):
        agent_name = get_agent_name(symbol)
        try:
            agent: Spi = self.agent_map[agent_name]
        except KeyError:
            err = 'Agent for {} not implemented!'.format(symbol)
            raise NotImplementedError(err)
        return agent


class BinanceFunctions(FunctionsRouter):
    def _create_agent(self):
        self.agent_map = {n: cls() for n, cls in _exchange_function_map.items()}

    def _get_agent(self, symbol):
        agent_name = get_agent_name(symbol)
        return self.agent_map[agent_name]


def get_agent_name(symbol):
    if '.' in symbol:
        return 'swap'
    else:
        return 'spot'


_channel_agent_map = {'spot': BinanceSpotChannel, 'swap': BinanceSwapUsdtChannel}
_handler_agent_map = {'spot': BinanceSpotHandler, 'swap': BinanceSwapUsdtHandler}
_api_agent_map = {'spot': BinanceSpotApi, 'swap': BinanceSwapUsdtApi}
_spi_agent_map = {'spot': BinanceSpotSpi, 'swap': BinanceSwapUsdtSpi}
_exchange_function_map = {'spot': BinanceSpotFunctions, 'swap': BinanceSwapFunctions}

add_factory(Exchange.Binance, BinanceChannel, BinanceHandler, BinanceApi, BinanceSpi, BinanceFunctions)


if __name__ == '__main__':
    def try_funcs():
        from quant.exchanges import get_factory

        binance_fac = get_factory('Binance')
        funcs = binance_fac.function_cls()
        a = funcs.get_all_ticker()
        li = list(a.items())

        li = sorted(li, key=lambda x: x[-1]['vol'], reverse=True)
        for i in li:
            print(i)

    def try_funcs_2():
        functions = BinanceFunctions()
        a = functions.get_value_factor('btc/usdt')
        print(a)

    try_funcs_2()
